﻿using KC.Framework.Util;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace KC.Storage.Util.Cache
{
    public class RedisDistributedLock : DistributedLockAbstract
    {
        /// <summary>
        ///  Redis的分布式锁
        /// </summary>
        /// <param name="key">锁的key</param>
        /// <param name="acquireTimeout">获取Key的超时时间</param>
        /// <param name="lockTimeOut">锁的过期时间</param>
        /// <param name="action"></param>
        public override void DoDistributedLock(string key, TimeSpan acquireTimeout, TimeSpan lockTimeOut, Action action)
        {
            key = DistributedLockPro + key;
            var value = Guid.NewGuid().ToString();

            var end = DateTime.UtcNow.Ticks + acquireTimeout.Ticks;
            var redisHelper = new RedisHelper(4);
            while (DateTime.UtcNow.Ticks < end)
            {
                if (redisHelper.TryGetDistributedLock(key, value, lockTimeOut))
                {
                    try
                    {
                        action();
                    }
                    finally
                    {
                        redisHelper.ReleaseDistributedLock(key, value);
                    }

                    return;
                }

                try
                {
                    System.Threading.Thread.Sleep(10);
                }
                catch (Exception e)
                {
                    LogUtil.LogException(e);
                    System.Threading.Thread.CurrentThread.Interrupt();
                }
            }
        }
        
        /// <summary>
        ///  Redis的分布式锁
        /// </summary>
        /// <param name="key">锁的key</param>
        /// <param name="acquireTimeout">获取Key的超时时间</param>
        /// <param name="lockTimeOut">锁的过期时间</param>
        /// <param name="action"></param>
        public override async Task DoDistributedLockAsync(string key, TimeSpan acquireTimeout, TimeSpan lockTimeOut, Action action)
        {
            key = DistributedLockPro + key;
            var value = Guid.NewGuid().ToString();

            var end = DateTime.UtcNow.Ticks + acquireTimeout.Ticks;
            var redisHelper = new RedisHelper(4);
            while (DateTime.UtcNow.Ticks < end)
            {
                if (await redisHelper.TryGetDistributedLockAsync(key, value, lockTimeOut))
                {
                    try
                    {
                        action();
                    }
                    finally
                    {
                        await redisHelper.ReleaseDistributedLockAsync(key, value);
                    }

                    return;
                }

                try
                {
                    await Task.Delay(10);
                    //System.Threading.Thread.Sleep(10);
                }
                catch (Exception e)
                {
                    LogUtil.LogException(e);
                    System.Threading.Thread.CurrentThread.Interrupt();
                }
            }
        }
    }
}
